home *** CD-ROM | disk | FTP | other *** search
- /* TextEditManager.c */
- /*
- * TextEditManager.c
- * Copyright © 1993 Apple Computer Inc. All rights reserved.
- *
- * These routines do some of the busy-work around a TextEdit handle.
- *
- * Note regarding Undo. Unfortunately, there is no refCon or similar in a TextEdit
- * record. This requires us to define a more complex structure (with a TextEdit
- * handle as one of its components) and the application must call a function
- * -- actually a macro -- to access the actual TextEdit handle.
- *
- */
- #include "LogManager.h"
- #ifndef THINK_C /* MPW includes */
- #include <Errors.h>
- #include <Script.h>
- #include <Types.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <Menus.h>
- #include <Scrap.h>
- #include <TextEdit.h>
- #endif
- #include "TextEditManager.h"
- #pragma segment TextEditManager
-
- #define width(r) ((r).right - (r).left)
- #define height(r) ((r).bottom - (r).top)
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
- #define kMargin 4 /* Inset from viewRect */
- #define EDIT (**editHandle)
- #define TEHANDLE (EDIT.teHandle)
- #define TEXT (**teHandle)
- #define EVENT (*eventRecord)
- /*
- * TextEdit understands these special characters.
- */
- enum {
- kDelete = 0x08, /* Backpace */
- kForwardDelete = 0x7F, /* Delete */
- kFirstArrow = 0x1C, /* Left arrow */
- kLastArrow = 0x1F /* Down arrow */
- };
-
- enum EditMenu {
- kEditUndo = 1,
- kEditUnused,
- kEditCut,
- kEditCopy,
- kEditPaste,
- kEditClear
- };
-
- /*
- * Local functions
- */
- static void SetupNewUndo(
- EditHandle editHandle,
- Boolean forceNewUndo,
- UndoAction undoAction
- );
- static void DoUndo(
- EditHandle editHandle
- );
-
- EditHandle
- CreateEditHandle(
- const Rect *viewRect,
- short fontNumber,
- short fontSize,
- short editMenuID,
- short undoTextResID,
- void *refCon
- )
- {
- register EditHandle editHandle;
- register TEHandle teHandle;
- Rect displayRect;
- Rect destRect;
-
- editHandle = (EditHandle) NewHandleClear(sizeof (EditRecord));
- if (editHandle != NULL) {
- EDIT.editMenuID = editMenuID;
- EDIT.undoTextResID = undoTextResID;
- EDIT.refCon = refCon;
- TextFont(fontNumber);
- TextSize(fontSize);
- TextFace(normal);
- displayRect = *viewRect;
- InsetRect(&displayRect, kMargin, kMargin);
- destRect = displayRect;
- destRect.right -= 2; /* TextEdit bug */
- destRect.bottom = 30000;
- teHandle = TENew(&destRect, &displayRect);
- if (teHandle == NULL) {
- DisposeHandle((Handle) editHandle);
- editHandle = NULL;
- }
- else {
- EDIT.teHandle = teHandle;
- TEAutoView(TRUE, teHandle);
- }
- }
- return (editHandle);
- }
-
- void
- DisposeEditHandle(
- EditHandle editHandle
- )
- {
- register TEHandle teHandle;
-
- if (editHandle != NULL) {
- if (EDIT.undoHandle != NULL)
- DisposeHandle((Handle) EDIT.undoHandle);
- teHandle = GetTEHandle(editHandle);
- if (teHandle != NULL)
- TEDispose(teHandle);
- DisposeHandle((Handle) editHandle);
- }
- }
-
- Boolean
- DoTextEditEvent(
- EditHandle editHandle,
- const EventRecord *eventRecord
- )
- {
- register TEHandle teHandle;
- Boolean result;
- GrafPtr savePort;
- unsigned short theChar;
- Point mousePt;
- Boolean extendSelection;
- #define EVENT (*eventRecord)
-
- teHandle = GetTEHandle(editHandle);
- result = FALSE;
- switch (EVENT.what) {
- case keyDown:
- case autoKey:
- if (TEXT.active != 0) {
- theChar = EVENT.message & charCodeMask;
- if (theChar >= kFirstArrow && theChar <= kLastArrow)
- EDIT.newUndo = TRUE; /* Mouse movement */
- else {
- SetupNewUndo(
- editHandle,
- (EDIT.undoAction != kUndoTyping),
- kUndoTyping
- );
- }
- TEKey(theChar, teHandle);
- result = TRUE;
- }
- break;
- case nullEvent:
- TEIdle(teHandle);
- break;
- case mouseDown:
- if (TEXT.active != 0 && (EVENT.modifiers & cmdKey) == 0) {
- GetPort(&savePort);
- SetPort(TEXT.inPort);
- mousePt = EVENT.where;
- GlobalToLocal(&mousePt);
- if (PtInRect(mousePt, &TEXT.viewRect)) {
- extendSelection = (EVENT.modifiers & shiftKey) != 0;
- TEClick(mousePt, extendSelection, teHandle);
- EDIT.newUndo = TRUE;
- result = TRUE;
- }
- SetPort(savePort);
- }
- break;
- default:
- break;
- }
- return (result);
- }
-
-
- Boolean
- AdjustEditMenu(
- EditHandle editHandle
- )
- {
- register TEHandle teHandle;
- MenuHandle editMenuHandle;
- Boolean hasSelection;
- long scrapLength;
- long scrapOffset;
- Boolean undoEnabled;
- Boolean result;
- Str255 undoText;
-
- teHandle = GetTEHandle(editHandle);
- editMenuHandle = GetMenu(EDIT.editMenuID);
- result = FALSE;
- if (editMenuHandle != NULL && TEXT.active != 0) {
- result = TRUE;
- DisableItem(editMenuHandle, kEditUndo);
- DisableItem(editMenuHandle, kEditCut);
- DisableItem(editMenuHandle, kEditCopy);
- DisableItem(editMenuHandle, kEditPaste);
- DisableItem(editMenuHandle, kEditClear);
- /*
- * Cut, Copy, and Clear are active if there's a selection.
- */
- hasSelection = (TEXT.selStart != TEXT.selEnd);
- if (hasSelection) {
- EnableItem(editMenuHandle, kEditCut);
- EnableItem(editMenuHandle, kEditCopy);
- EnableItem(editMenuHandle, kEditClear);
- }
- /*
- * Paste is active if there's something in the scrap.
- */
- scrapLength = GetScrap(NULL, 'TEXT', &scrapOffset);
- if (scrapLength > 0)
- EnableItem(editMenuHandle, kEditPaste);
- /*
- * Undo is active if there is a handle full of old junk.
- */
- undoEnabled = (EDIT.undoHandle != NULL);
- if (undoEnabled == FALSE)
- EDIT.undoAction = kUndoByItself;
- else {
- EnableItem(editMenuHandle, kEditUndo);
- }
- /*
- * Set the correct text in the Edit/Undo menu item.
- */
- GetIndString(undoText, EDIT.undoTextResID, EDIT.undoAction);
- SetItem(editMenuHandle, kEditUndo, undoText);
- }
- return (result);
- }
-
- /*
- * Note: this ignores a lot of error handling.
- */
- Boolean
- ManageEditMenu(
- EditHandle editHandle,
- short menuItem /* 1 = Undo, 3 = Cut, etc. */
- )
- {
- register TEHandle teHandle;
- GrafPtr savePort;
- Boolean result;
-
- teHandle = GetTEHandle(editHandle);
- result = (TEXT.active != 0);
- if (result) {
- GetPort(&savePort);
- SetPort(TEXT.inPort);
- switch (menuItem) {
- case kEditUndo:
- DoUndo(editHandle);
- break;
- case kEditCut:
- if (ZeroScrap() == noErr) {
- SetupNewUndo(editHandle, TRUE, kUndoCut);
- TECut(teHandle);
- (void) TEToScrap();
- }
- break;
- case kEditCopy:
- if (ZeroScrap() == noErr) {
- SetupNewUndo(editHandle, TRUE, kUndoCopy);
- TECopy(teHandle);
- (void) TEToScrap();
- }
- break;
- case kEditPaste:
- if (TEFromScrap() == noErr) {
- SetupNewUndo(editHandle, TRUE, kUndoPaste);
- TEPaste(teHandle);
- }
- break;
- case kEditClear:
- SetupNewUndo(editHandle, TRUE, kUndoClear);
- TEDelete(teHandle);
- break;
- default:
- result = FALSE;
- break;
- }
- SetPort(savePort);
- }
- return (result);
- }
-
- void
- RepositionEditItem(
- EditHandle editHandle,
- const Rect *viewRect
- )
- {
- register TEHandle teHandle;
- Rect displayRect;
- short newWidth;
- short newHeight;
-
- teHandle = GetTEHandle(editHandle);
- displayRect = *viewRect;
- InsetRect(&displayRect, kMargin, kMargin);
- newWidth = width(displayRect);
- newHeight = height(displayRect);
- InvalRect(&TEXT.viewRect);
- TEXT.viewRect.right = TEXT.viewRect.left + newWidth;
- TEXT.viewRect.bottom = TEXT.viewRect.top + newHeight;
- TEXT.destRect.right = TEXT.destRect.left + newWidth;
- OffsetRect(
- &TEXT.viewRect,
- displayRect.left - TEXT.viewRect.left,
- displayRect.top - TEXT.viewRect.top
- );
- OffsetRect(
- &TEXT.destRect,
- displayRect.left - TEXT.destRect.left,
- displayRect.top - TEXT.destRect.top
- );
- InvalRect(&TEXT.viewRect);
- }
-
- /*
- * Undo-related functions (private to TextEditManager.c)
- */
-
- /*
- * Save the current state of the TextEdit record so the user can Undo it later.
- */
- static void
- SetupNewUndo(
- EditHandle editHandle,
- Boolean forceNewUndo,
- UndoAction undoAction
- )
- {
- register TEHandle teHandle;
- Handle textHandle;
- Handle undoHandle;
-
- teHandle = GetTEHandle(editHandle);
- if (forceNewUndo || EDIT.newUndo) {
- textHandle = TEXT.hText;
- undoHandle = EDIT.undoHandle;
- /*
- * Since this is a new sequence, dump the old undo handle if present.
- */
- if (undoHandle != NULL) {
- DisposeHandle(undoHandle);
- EDIT.undoHandle = NULL;
- }
- /*
- * Copy the TextEdit handle. If successful, remember the selection.
- */
- undoHandle = textHandle;
- if (HandToHand(&undoHandle) == noErr) {
- EDIT.undoHandle = undoHandle;
- EDIT.newUndo = FALSE;
- EDIT.undoSelStart = TEXT.selStart;
- EDIT.undoSelEnd = TEXT.selEnd;
- EDIT.undoAction = undoAction;
- }
- }
- }
-
- /*
- * We know we're called with an active TextEdit record and the port is set
- * to the TextEdit port.
- */
- static void
- DoUndo(
- EditHandle editHandle
- )
- {
- register TEHandle teHandle;
- Handle textHandle;
- Handle undoHandle;
- short oldSelStart;
- short oldSelEnd;
- Rect viewRect;
-
- teHandle = GetTEHandle(editHandle);
- undoHandle = EDIT.undoHandle;
- if (undoHandle != NULL) {
- textHandle = TEXT.hText;
- oldSelStart = TEXT.selStart;
- oldSelEnd = TEXT.selEnd;
- /*
- * Swap the TEHandle with the UndoHandle. First, duplicate the
- * TextEdit handle. Then store the undo text in the TextEdit record.
- */
- if (HandToHand(&textHandle) == noErr) {
- HLock(undoHandle);
- TESetSelect(0, 0, teHandle);
- TESetText(*undoHandle, GetHandleSize(undoHandle), teHandle);
- DisposeHandle(undoHandle);
- TESetSelect(EDIT.undoSelStart, EDIT.undoSelEnd, teHandle);
- /*
- * Force an update so the text area looks like something
- * actually happened.'
- */
- viewRect = TEXT.viewRect;
- EraseRect(&viewRect);
- TEUpdate(&viewRect, teHandle);
- /*
- * Now, save the "undone" text in the undo buffer and flip
- * between Undo and Redo menu items.
- */
- EDIT.undoHandle = textHandle;
- EDIT.undoSelStart = oldSelStart;
- EDIT.undoSelEnd = oldSelEnd;
- EDIT.undoAction =
- (EDIT.undoAction <= kUndoClear)
- ? EDIT.undoAction + kUndoOffset
- : EDIT.undoAction - kUndoOffset;
- AdjustEditMenu(editHandle);
- }
- }
- }
-